//
//  GCDGroupViewController.m
//  多线程编程
//
//  Created by Guo Rui on 2017/7/14.
//  Copyright © 2017年 GR Harry. All rights reserved.
//

#import "GCDGroupViewController.h"

@interface GCDGroupViewController ()
@property (strong, nonatomic) NSMutableArray *resources;
@end

@implementation GCDGroupViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.resources = @[@"imageName1", @"imageName2", @"imageName3"].mutableCopy;
    
    dispatch_group_t group = dispatch_group_create();
    
//    [self baseOperation:group];
//    [self group_notify:group];
    [self barrier_async:group];
    
}

- (void)barrier_async:(dispatch_group_t)group {
    /*
     3. 正如我们文中所提到的，并发编程中不可避免的碰到资源争夺问题，解决这类问题有三种方法：
     
        - 加锁 @synchronized(//要锁对象){相关操作}
        - 使用异步执行串行队列的方式，这样可以控制对象的操作顺序
        - dispatch_barrier ，没错使用它也可以做到这一点
     
     在队列中，barrier 块必须单独执行，不能与其他 block 并行。这只对并发队列有意义，并发队列如果发现接下来要执行的 block 是个 barrier block，那么就一直要等到当前所有并发的 block 都执行完毕，才会单独执行这个barrier block代码块，等到这个barrier block执行完毕，再继续正常处理其他并发block。
     */
    
    dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    
    for (int i = 4; i < 100; i++) {
        dispatch_async(queue, ^{
            [self.resources addObject:[NSString stringWithFormat:@"imageName%zd", i]];
            NSLog(@"count %zd", self.resources.count);
        });
        
        dispatch_barrier_async(queue, ^{
            NSString *content = [self.resources lastObject];
            [self.resources removeObject:content];
            NSLog(@"%@", content);
        });
    }
}

- (void)group_notify:(dispatch_group_t)group {
    /*
        2. dispatch_group 执行完一组异步操作后可以通过 dispatch_group_notify来通知主线程，反馈信息给用户。
     
        dispatch_group_wait：会阻塞当前线程，等待所有任务完成。
        group_notify       ：不用阻塞当前线程，所有任务完成后可以 指定线程 做之后的操作。
     */
    dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        sleep(2);
        NSLog(@"任务完成");
    });
    
    NSLog(@"处理其他与任务无关的事情");
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"组内任务全部完成后，切到主线程进行操作");
    });
}

- (void)baseOperation:(dispatch_group_t)group {
    /*
     1. 使用 Dispatch Group 等待 queue 中的一组任务
    
     Dispatch group 用来阻塞一个线程，直到一个或多个任务完成执行。有时候 你必须等待任务完成的结果，然后才能继续后面的处理。
     */
    
    
    dispatch_queue_t queue1 = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("test,serialQueue", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"---start-----");
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_group_async(group, queue1, ^{
            sleep(1);
            NSLog(@"queue1 中的任务一完成");
        });
        
        dispatch_group_async(group, queue1, ^{
            sleep(1);
            NSLog(@"queue1 中的任务二完成");
        });
        
        dispatch_group_async(group, queue2, ^{
            sleep(1);
            NSLog(@"queue2 中的任务一完成");
        });
        
        // code 你可以在这里写代码做一些不必等待 group 内任务的操作
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        
        // 所有的任务都完成，可以做些任务都完成后的操作。
        NSLog(@"---wait after----");
        
    });

}

@end
